package com.lagou.edu.factory;

import com.lagou.edu.annotation.Transactional;
import com.lagou.edu.utils.TransactionManager;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.*;
import java.sql.SQLException;

/**
 * <p>
 * <p>
 * 代理对象工厂：生成代理对象的
 */
public class ProxyFactory {

    /**
     * Jdk动态代理
     *
     * @param obj 委托对象
     * @return 代理对象
     */
    public Object getJdkProxy(Object obj) {

        // 获取代理对象
        return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

                        for (Method declaredMethod : obj.getClass().getDeclaredMethods()) {
                            if (declaredMethod.getName().equals(method.getName()) && declaredMethod.getParameterCount() == method.getParameterCount()) {
                                boolean isFullMatch = true;
                                // 比较参数类型是否匹配
                                Type[] genericParameterTypes = declaredMethod.getGenericParameterTypes();
                                Type[] genericParameterTypes2 = method.getGenericParameterTypes();
                                for (int i = 0; i < genericParameterTypes.length; i++) {
                                    if (!genericParameterTypes[i].equals(genericParameterTypes2[i])) {
                                        isFullMatch = false;
                                        break;
                                    }
                                }
                                if (isFullMatch && declaredMethod.getDeclaredAnnotation(Transactional.class) != null) {
                                    return doTransactionInvoke(method, args, obj);
                                }
                            }
                        }
                        return method.invoke(obj, args);
                    }
                });
    }


    /**
     * 使用cglib动态代理生成代理对象
     *
     * @param obj 委托对象
     * @return
     */
    public Object getCglibProxy(Object obj) {
        return Enhancer.create(obj.getClass(), new MethodInterceptor() {
            @Override
            public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                if (method.getDeclaredAnnotation(Transactional.class) != null) {
                    return doTransactionInvoke(method, args, obj);
                } else {
                    return method.invoke(obj, args);
                }
            }
        });
    }

    /**
     * 执行事务方法
     *
     * @param method
     * @param args
     * @param obj
     * @return
     * @throws SQLException
     * @throws IllegalAccessException
     * @throws InvocationTargetException
     */
    private Object doTransactionInvoke(Method method, Object[] args, Object obj) throws SQLException, IllegalAccessException, InvocationTargetException {
        Object result = null;
        TransactionManager transactionManager = (TransactionManager) BeanFactory.getBean(TransactionManager.class);
        try {
            // 开启事务(关闭事务的自动提交)
            transactionManager.beginTransaction();

            result = method.invoke(obj, args);

            // 提交事务
            transactionManager.commit();
        } catch (Exception e) {
            e.printStackTrace();
            // 回滚事务
            transactionManager.rollback();
            // 抛出异常便于上层servlet捕获
            throw e;
        }
        return result;
    }
}
